// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Defines the background script for test_extension.  The
 * test_extension is a Chrome Extension that tests the Chrome Extension API is
 * working as expected.  The extension is loaded in Chrome and then compared to
 * the Mimic wrapped version for non-Chrome browsers to ensure that they
 * produce the same results.
 *
 * @author jasonstredwick@google.com (Jason Stredwick)
 */


/**
 * Maintains a global reference to the connection between the background and
 * content scripts.
 * @type {Object}
 * @private
 */
var port_ = null;


/**
 * Handles a request through a connection.
 * @param {Object} request The request object.
 */
function handleConnectionRequest(request) {
  if (!request) {
    console.log('No request received.');
    return;
  } else if (!request['msg']) {
    console.log('No message received.');
    return;
  }

  switch (request['msg']) {
    case 'ping':
      port_.postMessage({'msg': 'Hi from background'});
      break;

    default:
      console.log('Received message from port(' + port_.name + ')' +
                  request['msg']);
      port_.postMessage({'msg': request['msg']});
  }
}


/**
 * Handles a request to connect from chrome.extension.connect.
 * @param {Object} port The port object contains the necessary information to
 *     provide a lasting communication channel between two script units.
 */
function handleOnConnect(port) {
  if (!port) {
    return;
  }

  console.log('Background received connection from content script.');

  port_ = port;
  port_.onMessage.addListener(handleConnectionRequest);
}


/**
 * Handles a request from another script unit using
 * chrome.extension.sendRequest.
 * @param {Object} request The request object.
 * @param {Object} sender An object containing information about the sender.
 * @param {Function=} opt_response An optional callback function.
 */
function handleOnRequest(request, sender, opt_response) {
  if (!request) {
    console.log('No request received.');
    return;
  } else if (!request['msg']) {
    console.log('No message received.');
    return;
  }

  var fromTab = sender.tab ? true : false;
  var extId = sender.id;

  switch (request['msg']) {
    case 'ping':
      if (sender.tab) {
        console.log('Received ping from ' + sender.tab.id);
        chrome.tabs.sendRequest(sender.tab.id, {'msg': 'Hi from background'},
            function() {
              console.log('Received Response from ' + sender.tab.id);
            });
      }
      break;

    case 'browserAction':
      var baType = request['type'];
      var baValue = request['value'];
      switch (baType) {
        case 'badgeText':
          chrome.browserAction.setBadgeText({'text': baValue});
          break;
        case 'badgeColor':
          chrome.browserAction.setBadgeBackgroundColor(
              {'color': convertColor(baValue.substr(1).toLowerCase())});
          break;
        case 'title':
          chrome.browserAction.setTitle({'title': baValue});
          break;
        default:
          console.error('ERROR: Invalid browserAction change: ' + baType);
          break;
      }
      break;

    case 'windowCreate':
      var winData = request['value'];
      chrome.windows.create(winData,
                            (!opt_response) ? function() {} : function(win) {
        opt_response(win);
      });
      break;

    case 'options':
      console.log('Received update from options page.');
      var keys = request['keys'];
      for (var i = 0; i < keys.length; ++i) {
        console.log(keys[i] + ': ' + localStorage.getItem(keys[i]));
      }
      break;

    case 'url':
      if (opt_response) {
        switch (request['url']) {
          case 'base':
            opt_response({'respMsg': chrome.extension.getURL('')});
            break;
          case 'url1':
            opt_response(
                {'respMsg': chrome.extension.getURL('/path/file1.html')});
            break;
          case 'url2':
            opt_response(
                {'respMsg': chrome.extension.getURL('path/file2.html')});
            break;
        }
      }
      break;

    case 'xss':
      var xhr = new XMLHttpRequest();
      xhr.open('GET', request['url'], false);
      try {
        xhr.send();
      } catch (error) {
        opt_response && opt_response({'respMsg': 'Failed to send request.'});
        break;
      }

      if (xhr.status != 200 && xhr.status != 0) {
        opt_response && opt_response(
            {'respMsg': 'Request failed with status: ' + xhr.status});
        break;
      }

      opt_response && opt_response({'respMsg': xhr.responseText});
      break;

    default:
      console.log('Received message from extension(' + extId + ')' +
          (fromTab ? ' and tab(' + sender.tab.id + ')' : '') +
          ': ' + request['msg']);
      if (opt_response) {
        opt_response({'respMsg': request['msg']});
      }
  }
}


/**
 * Converts a three or six hex digit value into a rgba array.  The rgba array
 * values will be clamped to from 0 to 255.
 * @param {string} value The hex digit number code.
 * @return {Array.<number>} The rgba color array.
 */
function convertColor(value) {
  if (typeof(value) == 'string') {
    if (value.length == 3) {
      return [convertHex1(value[0]) / 15 * 255,
              convertHex1(value[1]) / 15 * 255,
              convertHex1(value[2]) / 15 * 255,
              255];
    } else if (value.length == 6) {
      return [convertHex1(value[0]) * 16 + convertHex1(value[1]),
              convertHex1(value[2]) * 16 + convertHex1(value[3]),
              convertHex1(value[4]) * 16 + convertHex1(value[5]),
              255];
    }
  }

  return [0, 0, 0, 255];
}


/**
 * Converts a single hex digit into a base 10 value.
 * @param {string} value A single character that represents a hex digit.  Any
 *     other value will be converted to zero.
 * @return {number} The base 10 value.
 */
function convertHex1(value) {
  switch (value) {
    case '0':
      return 0;
    case '1':
      return 1;
    case '2':
      return 2;
    case '3':
      return 3;
    case '4':
      return 4;
    case '5':
      return 5;
    case '6':
      return 6;
    case '7':
      return 7;
    case '8':
      return 8;
    case '9':
      return 9;
    case 'a':
      return 10;
    case 'b':
      return 11;
    case 'c':
      return 12;
    case 'd':
      return 13;
    case 'e':
      return 14;
    case 'f':
      return 15;
  }

  return 0;
}


/**
 * Set up listeners for the extension.
 */
chrome.extension.onConnect.addListener(handleOnConnect);
chrome.extension.onRequest.addListener(handleOnRequest);

